#include "directedgraph.h"

using namespace core;

DirectedGraph::DirectedGraph(bool handleMemory) :
    m_handleMemory(handleMemory),
    m_nodes()
{

}

DirectedGraph::~DirectedGraph()
{
    clear();
}

Edge* DirectedGraph::connect(Node* from, Node* to, IEdgeData* data)
{
    Edge* edge = 0;

    QPair<Node*, Node* > key(from, to);

    if (!m_edges.contains(key))
    {
        edge = Edge::create(from, to, data);

        m_edges.insert(key, edge);

        m_nodes.insert(from);
        m_nodes.insert(to);

        from->addOutgoing(to);
        to->addIncoming(from);
    }
    else
    {
        edge = m_edges[key];
    }

    return edge;
}

void DirectedGraph::disconnect(Node*& from, Node*& to)
{
    QPair<Node*, Node* > key(from, to);

    if (m_edges.contains(key))
    {
        from->removeOutgoing(to);
        to->removeIncoming(from);

        Edge* edge = m_edges[key];
        m_edges.remove(key);

        delete edge;

        if (m_handleMemory)
        {
            if (from->getIncomingConnections().size() == 0 &&
                from->getOutgoingConnections().size() == 0)
            {
                m_nodes.remove(from);
                delete from;
                from = 0;
            }

            if (to->getIncomingConnections().size() == 0 &&
                to->getOutgoingConnections().size() == 0)
            {
                m_nodes.remove(to);
                delete to;
                to = 0;
            }
        }
    }
}

bool DirectedGraph::removeNode(Node* node)
{
    return m_nodes.remove(node);
}

QSet<Node* > DirectedGraph::getNodes() const
{
    return m_nodes;
}

Edge* DirectedGraph::getEdge(Node* from, Node* to) const
{
    Edge* edge = 0;

    QPair<Node*, Node* > key(from, to);

    if (m_edges.contains(key))
    {
        edge = m_edges[key];
    }

    return edge;
}

void DirectedGraph::clear()
{
    foreach (Node* node, m_nodes)
    {
        delete node;
        node = 0;
    }

    m_nodes.clear();

    foreach (Edge* edge, m_edges)
    {
        delete edge;
        edge = 0;
    }

    m_edges.clear();
}
